/*
  (C) 2005 Adam D. Bradley

  This program is free software; you can redistribute it and/or
  modify it under the terms of Version 2 of the GNU General Public 
  License.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.
  
  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

package snbenchlib;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import javax.xml.parsers.*;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import step.parse.SyntaxError;

/**
 * This is a helper class for generating XML parsers and the like.
 */
public final class XML
{
	private static DocumentBuilderFactory factory = null;

	public static String XMLNS = 
		"http://www.cs.bu.edu/snbench/WP-SNBENCH-20050712";
	public static String XMLHead = 
		"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
	public static String XMLStyle =
		"<?xml-stylesheet href=\"/snbench/markup/sxe20050712.xsl\"" + 
		" type=\"text/xsl\" media=\"screen\" ?>\n";
	
	public static String THISID;
	

	/**
	 * Returns the XML element that is the root of the XML contained in sXMLtoBeParsed.
	 * If the root/document element does not have tag matching sElementTag
	 * 
	 * @param sXMLtoBeParsed
	 * @param sElementTag
	 * @return
	 * @throws NullPointerException
	 * @throws SyntaxError
	 */
	public static Element parseXMLAndReturnRootElement(String sXMLtoBeParsed, String sElementTag) throws
		NullPointerException, SyntaxError
	{
		Document d = null;
		Element elem = null;
		
		if(sXMLtoBeParsed==null)
			throw new NullPointerException("returnRootElementOfXML called with null XML string");

		try {
			ByteArrayInputStream bais = new ByteArrayInputStream(sXMLtoBeParsed.getBytes());
			d = XML.getDocumentBuilder().parse(bais);
			elem = d.getDocumentElement();

			if(!elem.getNodeName().equalsIgnoreCase(sElementTag))
				throw new SyntaxError("Root element of XML did not match expected element tag (" + elem.getNodeName() + ") is not the requested " + sElementTag );
			return elem;
			
		} catch (SAXException e) {
			e.printStackTrace();
			throw new SyntaxError(e.getMessage());
		} catch (IOException e) {
			e.printStackTrace();
			throw new SyntaxError(e.getMessage());
		}
	}

	/**
	 * Returns the XML element that is the root of the XML contained in file.
	 * If the root/document element does not have tag matching sElementTag
	 * 
	 * @param file
	 * @param sElementTag
	 * @return
	 * @throws NullPointerException
	 * @throws SyntaxError
	 */
	public static Element parseXMLAndReturnRootElement(File file, String sElementTag) throws
		NullPointerException, SyntaxError
	{
		Document d = null;
		Element elem = null;

		if(file==null)
			throw new NullPointerException("returnRootElementOfXML called with null file");
		
		try {
			FileInputStream fis = new FileInputStream(file);
			d = XML.getDocumentBuilder().parse(fis);
			elem = d.getDocumentElement();
			
			if(!elem.getNodeName().equalsIgnoreCase(sElementTag))
				throw new SyntaxError("Root element of XML did not match expected element tag (" + elem.getNodeName() + ") is not the requested " + sElementTag );
			return elem;
			
		} catch (SAXException e) {
			e.printStackTrace();
			throw new SyntaxError(e.getMessage());
		} catch (IOException e) {
			e.printStackTrace();
			throw new SyntaxError(e.getMessage());
		}
	}
	
	public static final Node getChildNodeMatchingTag(Element eParent, String tagOfChild){
		for(Node c = eParent.getFirstChild();c!=null;c = c.getNextSibling()){
			if(c.getNodeName().equals(tagOfChild))
				return c;
		}
		return null;			
	}
	
	public static final DocumentBuilder getDocumentBuilder() {
		DocumentBuilder result = null;
		try {
			if (factory == null) {
				factory = DocumentBuilderFactory.newInstance();
				factory.setValidating(false);
				factory.setIgnoringComments(true);
				factory.setCoalescing(true);
			}
			result = factory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			System.err.println(e.getMessage());
			System.exit(-1);
		}
		return result;
	}

	/** returns an XML string : <tag>content</tag> with "content"-
	 * many leading spaces.  Pure convienence.  Nothing more. */ 
	public static String tagger(int indent, String tag, String content){
		String space = "";
		for(int i=0;i<indent;i++)
			space+=" ";
	
		return space + "<" + tag + ">" +  content + "</" + tag + ">\n";
	}
	
	/** returns a string of the (first) text node child for the given node */
	public static String getStringChild(Node n){
		NodeList nl = n.getChildNodes();
		Node t = null;
		for(int i = 0; i < nl.getLength() ; i ++){
			t = nl.item(i);
			if(t.getNodeType() == Node.TEXT_NODE){
				return t.getNodeValue();
			}
		}
		return null;
	}
}